package org.jeecg.modules.system.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.HttpServletRequestUtil;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.common.vo.RequestVo;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.AppDeviceFreeze;
import org.jeecg.modules.system.entity.AppUserDeviceLog;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.AuthenticationModel;
import org.jeecg.modules.system.model.SysLoginPhoneModel;
import org.jeecg.modules.system.model.UserRegisterModel;
import org.jeecg.modules.system.service.IAppDeviceFreezeService;
import org.jeecg.modules.system.service.IAppUserDeviceLogService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.util.InviteCodeGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * <p>
 * APP用户管理 前端控制器
 * </p>
 *
 * @Author 苏涛
 * @since 2025年4月13日
 */
@Slf4j
@RestController
@RequestMapping("/app/user")
@Api(tags = "APP 用户管理")
public class AppUserController {

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private RedisUtil redisUtil;

    @Resource
    private BaseCommonService baseCommonService;

    @Resource
    private IAppDeviceFreezeService deviceFreezeService;

    @Resource
    private IAppUserDeviceLogService deviceLogService;

    @ApiOperation("APP登录接口-手机号登录")
    @RequestMapping(value = "/loginPhone", method = RequestMethod.POST)
    @IgnoreAuth
    public Result<JSONObject> loginPhone(@RequestBody SysLoginPhoneModel sysLoginModel, HttpServletRequest request) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();
        if (isLoginFailOvertimes(username)) {
            return result.error500("该用户登录失败次数过多，请于10分钟后再次登录！");
        }

        Enumeration<String> headers = request.getHeaderNames();
        while (headers.hasMoreElements()) {
            String name = headers.nextElement();
            String value = request.getHeader(name);
            System.out.println(name + "=" + value);
        }
        RequestVo deviceInfoVo = HttpServletRequestUtil.getDeviceInfoVo(request);
        List<AppDeviceFreeze> deviceFreezeList = deviceFreezeService.getList();

        if (deviceFreezeList != null && deviceFreezeList.size() > 0) {
            long count = deviceFreezeList.stream()
                    .filter(x -> x.getDeviceId().equals(deviceInfoVo.getDeviceId()) && x.getStatus().equals("0")).count();
            if (count > 0) {
                result.error500("请使用其他设备登录！");
                return result;
            }
        }

        if (StringUtils.isEmpty(deviceInfoVo.getVersionCode())) {
            result.error500("APP异常，请下载正版软件！");
            return result;
        }

        if (Integer.parseInt(deviceInfoVo.getVersionCode()) <= 28) {
            result.error500("APP版本过低，请更新最新版本！");
            return result;
        }

        // step.2 校验用户是否存在且有效
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = sysUserService.getOne(queryWrapper);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        // step.3 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            addLoginFailOvertimes(username);
            result.error500("用户名或密码错误");
            return result;
        }

        // step.3.1 验证用户状态
        if (!sysUser.getStatus().equals(CommonConstant.USER_UNFREEZE)) {
            result.error500("用户状态异常");
            return result;
        }
        AppUserDeviceLog deviceInfo = new AppUserDeviceLog();
        BeanUtils.copyProperties(deviceInfoVo, deviceInfo);
        deviceInfo.setUserId(sysUser.getId());
        deviceInfo.setRequestUrl("用户登录");
        deviceLogService.save(deviceInfo);

        sysUser.setClientId(deviceInfoVo.getDeviceId());
        sysUserService.updateById(sysUser);

        // step.4  登录成功获取用户信息
        userInfo(sysUser, result, request);

        // step.6  记录用户登录日志
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        baseCommonService.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        return result;
    }


    /**
     * 登录失败超出次数5 返回true
     *
     * @param username
     * @return
     */
    private boolean isLoginFailOvertimes(String username) {
        String key = CommonConstant.LOGIN_FAIL + username;
        Object failTime = redisUtil.get(key);
        if (failTime != null) {
            Integer val = Integer.parseInt(failTime.toString());
            if (val > 5) {
                return true;
            }
        }
        return false;
    }

    /**
     * 记录登录失败次数
     *
     * @param username
     */
    private void addLoginFailOvertimes(String username) {
        String key = CommonConstant.LOGIN_FAIL + username;
        Object failTime = redisUtil.get(key);
        Integer val = 0;
        if (failTime != null) {
            val = Integer.parseInt(failTime.toString());
        }
        // 10分钟，一分钟为60s
        redisUtil.set(key, ++val, 600);
    }


    /**
     * 用户信息
     *
     * @param sysUser
     * @param result
     * @return
     */
    private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result, HttpServletRequest request) {
        String username = sysUser.getUsername();
        String syspassword = sysUser.getPassword();
        // 获取用户部门信息
        JSONObject obj = new JSONObject(new LinkedHashMap<>());

        //1.生成token
        String token = JwtUtil.sign(username, syspassword);
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
        obj.put("token", token);

        //2.设置登录租户
        Result<JSONObject> loginTenantError = sysUserService.setLoginTenant(sysUser, obj, username, result);
        if (loginTenantError != null) {
            return loginTenantError;
        }

        //3.设置登录用户信息
        obj.put("userInfo", sysUser);

        result.setResult(obj);
        result.success("登录成功");
        return result;
    }


    /**
     * 用户注册接口
     *
     * @param registerModel
     * @return
     */
    @PostMapping("/register")
    @ApiOperation("APP用户注册接口")
    @IgnoreAuth
    public Result<JSONObject> userRegister(@RequestBody UserRegisterModel registerModel) {
        Result<JSONObject> result = new Result<JSONObject>();
        String phone = registerModel.getUsername();
        //未设置密码，则随机生成一个密码
        String password = registerModel.getPassword();
        SysUser sysUser1 = sysUserService.getUserByName(phone);
        if (sysUser1 != null) {
            result.setMessage("用户名已注册");
            result.setSuccess(false);
            return result;
        }
        SysUser sysUser2 = sysUserService.getUserByPhone(phone);
        if (sysUser2 != null) {
            result.setMessage("该手机号已注册");
            result.setSuccess(false);
            return result;
        }
        SysUser sysUser3 = sysUserService.getUserByGenCode(registerModel.getGenCode()); // 获取邀请人信息
        if (sysUser3 == null) {
            result.setMessage("未查到邀请人信息！");
            result.setSuccess(false);
            return result;
        }
        SysUser user = new SysUser();
        try {
            user.setCreateTime(new Date());// 设置创建时间
            String salt = oConvertUtils.randomGen(8);
            String passwordEncode = PasswordUtil.encrypt(phone, password, salt);
            user.setSalt(salt);
            user.setUsername(phone);
            user.setRealname("");
            user.setGenCode(gen());                     // 生成用户邀请码
            user.setPassword(passwordEncode);
            user.setEmail(phone + "@qq.com");
            user.setPhone(phone);
            user.setParentUser(registerModel.getGenCode());
            user.setStatus(CommonConstant.USER_UNFREEZE);
            user.setDelFlag(CommonConstant.DEL_FLAG_0);
            user.setActivitiSync(CommonConstant.ACT_SYNC_1);
            user.setCommissionRate(0.7d);
            user.setTeamCommissionRate(0.1);
            user.setTeamCommissionType("1");       // 团队奖励可转工币
            user.setOrgCode(sysUser3.getOrgCode());
            sysUserService.addUserWithRole(user, "ee8626f80f7c2619917b6236f3a7f02b");//默认临时角色 APP用户
            result.success("注册成功");
        } catch (Exception e) {
            result.error500("注册失败");
        }
        return result;
    }

    @GetMapping("/getGen")
    @ApiOperation(value = "获取当前用户的邀请码")
    public Result<String> getGen() {
        return Result.ok(gen());
    }

    /**
     * 获取当前用户的邀请码
     *
     * @return
     */
    @GetMapping("/queryCurrentGenCode")
    @ApiOperation(value = "获取当前用户的邀请码")
    public Result<String> queryCurrentGenCode() {
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        SysUser user = sysUserService.getById(loginUser.getId());
        return Result.ok(user.getGenCode());
    }

    @GetMapping("/queryUserAvatar")
    @ApiOperation(value = "获取用户头像")
    @IgnoreAuth
    public Result<String> queryUserAvatar(@RequestParam(name = "username", required = true) String username) {
        if (StringUtils.isNotEmpty(username)) {
            SysUser user = sysUserService.getUserByName(username);
            if (user != null)
                return Result.ok(user.getAvatar());
            return Result.ok("");
        }
        return Result.ok("");
    }

    /**
     * 用户手机号验证
     */
    @PostMapping("/phoneVerification")
    public Result<Map<String, String>> phoneVerification(@RequestBody JSONObject jsonObject) {
        Result<Map<String, String>> result = new Result<Map<String, String>>();
        String phone = jsonObject.getString("phone");
        String smscode = jsonObject.getString("smscode");
        //update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
        String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE + phone;
        Object code = redisUtil.get(redisKey);
        if (!smscode.equals(code)) {
            result.setMessage("手机验证码错误");
            result.setSuccess(false);
            return result;
        }
        //设置有效时间
        redisUtil.set(redisKey, smscode, 600);
        //update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
        //新增查询用户名
        LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
        query.eq(SysUser::getPhone, phone);
        SysUser user = sysUserService.getOne(query);
        Map<String, String> map = new HashMap(5);
        map.put("smscode", smscode);
        if (null == user) {
            //前端根据文字做判断用户是否存在判断，不能修改
            result.setMessage("用户信息不存在");
            result.setSuccess(false);
            return result;
        }
        map.put("username", user.getUsername());
        result.setResult(map);
        result.setSuccess(true);
        return result;
    }


    @AutoLog(value = "用户实名认证")
    @ApiOperation(value = "用户实名认证", notes = "用户实名认证")
    @PostMapping(value = "/authentication")
    @IgnoreAuth
    public Result<JSONObject> authentication(@RequestBody AuthenticationModel model) {
        Result<JSONObject> result = new Result<JSONObject>();
        SysUser user = sysUserService.getUserByName(model.getUserName());
//        user.setIdCard(model.getIdCard());
//        user.setRealname(model.getRealname());
        // 判断身份证是否已经存在
//        SysUser user2 = sysUserService.getUserByIdCard(model.getIdCard());
//        if (user2 != null) {
//            result.setMessage("该身份证号码已被注册，请重新输入！");
//            result.setSuccess(false);
//            return result;
//        }
        user.setAvatar(model.getPath());
        sysUserService.updateById(user);
        return Result.ok("更新个人信息成功");
    }

    @AutoLog(value = "提交付款码")
    @ApiOperation(value = "提交付款码", notes = "提交付款码")
    @PostMapping(value = "/submitAvatar")
    public Result<JSONObject> submitAvatar(@RequestBody AuthenticationModel model) {
        Result<JSONObject> result = new Result<JSONObject>();
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        SysUser user = sysUserService.getById(loginUser.getId());
        user.setAvatar(model.getPath());
        sysUserService.updateById(user);
        return Result.ok("更新个人信息成功");
    }

    @GetMapping("/queryUserAvatar2")
    @ApiOperation(value = "获取用户头像--需要授权")
    public Result<String> queryUserAvatar2() {
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        SysUser user = sysUserService.getById(loginUser.getId());
        return Result.ok(user.getAvatar());
    }

    @AutoLog(value = "查询用户实名认证信息")
    @ApiOperation(value = "查询用户实名认证信息", notes = "查询用户实名认证信息")
    @GetMapping(value = "/queryAuthentication")
    public Result queryAuthentication() {
        AuthenticationModel result = new AuthenticationModel();
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        SysUser user = sysUserService.getById(loginUser.getId());
        if (user != null) {
            result.setRealname(user.getRealname());
            result.setIdCard(user.getIdCard());
        }
        return Result.ok(result);
    }


    private String gen() {
        String gen = InviteCodeGenerator.generateInviteCode();
        // 判断邀请码是否存在
        LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(SysUser::getGenCode, gen);
        long count = this.sysUserService.count(queryWrapper);
        if (count > 0) {
            return gen();
        } else return gen;
    }

}
